home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-01-25 | 69.2 KB | 1,461 lines |
-
-
- Logical Operators
- Professional Software Development
- & Computer Consultation
-
- 707-A Dunbar Avenue
- P.O. Box 815
- Dunbar WV 25064-0815
- Telephone: (304)768-5079
-
- THE ALERTDRIVER C++ CLASS LIBRARY
- EXCERPTS FROM USER'S GUIDE
- Version 1.00
-
- References to businesses, organizations, and individuals
- within this publication are supplied only for informational
- purposes and in no way imply or infer endorsement or
- recommendation of the products and/or services of Logical
- Operators or its associates or affiliates unless explicitly
- stated.
-
- All brand names, trademarks, and registered trademarks
- appearing throughout this document are properties of their
- respective owners. The AlertDriver Class Library source
- code, object code, and all associated documentation are
- copyrighted 1994 by Logical Operators. All Rights Reserved.
- Part number ADUG940125.
-
-
-
- Preface
-
-
- At Logical Operators, we encountered many problems, portability
- issues, and maintenance issues when writing error-reporting
- code for the reusable libraries used in our applications. Nested
- if-then-else code detracted from the clarity of algorithms,
- hard-coded error messages caused reusability problems, and
- re-routing messages from the screen to other devices (such as
- printers) was difficult to say the least.
-
- Our solution to these problems, the AlertDriver Class Library,
- avoids all of these problems while providing a new software
- library with modularity, encapsulation, a consistent call
- interface, and efficient code size and speed. The AlertDriver
- Class Library is reusable and extensible to multiple application
- environments and hardware configurations. And perhaps most
- importantly, this easy-to-use class library provides the
- flexibility of multiple error-reporting methods within the same
- program while including the capability to easily enable, disable,
- or change reporting methods at both compile-time and run-time!
-
-
-
- Chapter 2 AlertDriver Class Library Concepts
-
-
- More Than Just Errors
-
- The AlertDriver Class Library does more than just simple
- error-reporting, it alerts the user to virtually any program
- condition during execution (hence the name). There are
- several types of program conditions, or alerts, which you
- may wish to present to the user during program execution:
- errors, information, messages, and warnings.
-
- Errors, the most serious types of alerts, occur when a
- program detects a state which makes continuation of the
- current branch of execution impossible. In interactive
- applications, an error usually stops program execution until
- acknowledged by the user. A typical error might be: "Cannot
- find file C:\YOURFILE.DAT."
-
- Information alerts occur whenever an application informs the
- user of a program condition or the occurrence of an event.
- Information alerts do not reflect execution problems and
- exist only for the convenience of the user. In interactive
- applications, an information alert stops program execution
- until acknowledged by the user. A typical information alert
- might be: "File C:\YOURFILE.DAT was successfully loaded."
-
- Messages also occur when the application informs the user of
- a program condition. Like information alerts, messages do
- not reflect execution problems and exist only for the
- convenience of the user. Unlike information alerts, messages
- do not stop program execution in interactive applications.
- Once posted, a message remains active until replaced by
- another message or cleared by the application. A sample
- message might be: "Loading file C:\YOURFILE.DAT..."
-
- Warnings (sometimes referred to as confirmations) are
- reported when the application prompts the user for a
- decision. Warnings are typically posed as a question with
- three possible answers: YES, NO, or CANCEL. Warnings pause
- program execution until the user makes a decision, then
- continue program execution based upon that decision. A
- common warning is "Do you want to overwrite file
- C:\YOURFILE.DAT?"
-
- Although the AlertDriver Class Library provides the means to
- deal with all of these types of alerts, this chapter will
- concentrate only on error handling to simplify the
- discussion. Please keep in mind that the concepts of error
- handling also apply to each of the other types of alerts.
-
-
- The AlertableObject Concept
-
- In most class libraries, the majority of classes are
- ultimately descendants of a single root class (usually named
- something like Object and having little actual
- functionality). Most new classes created by users of the
- library inherit the properties of an existing class, even if
- the class is as basic as Object. Thus, most objects (or
- class instantiations) in an application can be referenced
- and treated as a lowest common denominator - an Object.
-
- Now let's suppose that the root class has the ability to
- report errors it encounters during method executions. If
- such a class exists, it becomes easy to derive more
- specialized classes while simply inheriting the ability to
- report errors. Our programs can invoke the member functions
- of an object, knowing that if an error occurs, the object
- itself will report the problem to the user! Our programs
- only need to be aware of the success or failure of the
- member function's execution.
-
- If such a capability could be added to the root class of a
- commercial application framework, then the majority of the
- framework's classes (and their descendants) would be capable
- of reporting their errors to the user in a standardized
- manner right out of the box without any additional
- programming! Of course, not every programmer would have
- access to the framework's source code to implement this, and
- we may not want to add additional overhead to such a
- rudimentary class anyway. So in the true spirit of object-
- oriented programming, we would design a new class which
- directly inherits the capabilities of the framework's Object
- counterpart and adds some basic error-handling capabilities
- (see Example 4).
-
- Example 4 - A sample class declaration which could add error-
- handling capabilities to the base class (Object) of an
- application framework. The AlertDriver class library creates
- an error-handling class in a similar manner.
-
- class AlertableObject : public Object
- {
- /*add member functions below to
- enable error handling*/
- ...
- }; //class AlertableObject
-
- The AlertDriver Class Library includes a class similar to
- that in Example 4 and implements the class in such a way
- that it can either be used without a class hierarchy or
- integrated into practically any C++ class library: new or
- existing, commercial or private. We have named this class
- AlertableObject: it provides the functionality to alert the
- user of errors. By serving as a base class, AlertableObject
- provides a common calling interface to our error-handling
- member functions. In addition, because AlertableObject
- contains a public member function interface, our error-
- handling routines are accessible from program code
- throughout the application.
-
-
- Benefiting From AlertableObject
-
- By making AlertableObject a direct descendant of a
- framework's root class in the class hierarchy, error-
- handling capabilities can easily be inherited by your
- classes and their descendants. Of course, classes which are
- derived from the root class (and bypass AlertableObject,
- like the existing classes in the framework) will not inherit
- the error-handling capabilities.
-
- So what other benefits exist from using the AlertableObject
- class in an application? Suppose we have a code module which
- has just invoked a member function of a descendant of
- AlertableObject. Our calling module does not report any
- errors which occur within the object's member function
- (that's the object's responsibility). However, our calling
- module may be interested in determining if the member
- function was able to execute successfully, and if not, why.
-
- This simple scenario is an excellent reason to have an
- object's member functions return error codes. It is easy to
- declare a group of constants which represent error
- conditions for each class (see Example 5). Not only does
- this practice enforce good programming by removing hard-
- coded values from the member functions and calling modules,
- but a wide range of values can be represented within the
- code returned by each member function. In addition, returned
- error codes remove the need for an unnecessary global
- variable (such as errno) or class data member to store the
- most recent result of a method execution.
-
- Example 5 - Error constants can easily be created and
- returned from AlertableObjects.
-
- const long int NOERR = 0;
- const long int FILENOTFOUND = 1;
- const long int OUTOFMEMORY = 2;
- ...
- class MyObj : public AlertableObject
- {
- public:
- virtual long int MemFunc1(void);
- //returns error code
- ...
- }; //class MyObj
-
- By testing the returned error codes, the module calling such
- member functions can smoothly recover from errors occurring
- within the object while avoiding the "matching-else"
- syndrome for error reporting (see Example 6). A pleasant
- side-effect is that the source code becomes much more
- readable and understandable.
-
- Example 6 - The same algorithm used in Example 1 is
- implemented here, using calls to an object's member
- functions rather than "plain" function calls. The object
- MyObj is derived from class AlertableObject, allowing MyObj
- to report errors to the user when they occur. Notice how
- much more readable the code below appears than the code of
- Example 1.
-
- ...
- if (MyObj.func1() == NOERR)
- if (MyObj.func2() == NOERR)
- if (MyObj.func3() == NOERR)
- ...
-
- Perhaps the biggest benefit of the AlertableObject, however,
- lies in its encapsulation. Because the object is self-
- contained and able to report its own errors in a platform-
- independent manner, it can be linked into multiple
- applications, none of which has to deal with reporting the
- errors which could occur internally. Imagine how much easier
- your next programming project would be if you could simply
- plug some of your existing classes together and forget about
- handling the errors, confident that they will be handled
- automatically! With the AlertDriver Class Library, you can!
-
-
- Introducing The AlertDriver
-
- The AlertDriver is the class in the hierarchy which provides
- the platform- and hardware-dependent error-reporting
- capabilities to objects derived from AlertableObject. Each
- object derived from AlertableObject uses an AlertDriver
- object to perform the actual reporting of each error
- message. The AlertDriver object determines how each error
- message is reported using the API (application programming
- interface) calls and hardware available to the application;
- hence, each AlertDriver object is an "error device driver"
- for the application environment. Because AlertDrivers are
- implemented as classes, any AlertDriver can be subclassed by
- the application programmer to change or control its specific
- actions.
-
- The AlertDriver class library supplies classes which can be
- used to report errors to the screen for interactive
- applications, or log errors to a printer or disk file for
- programs which normally run without human supervision.
- Additional AlertDrivers can be obtained or written for other
- platforms and/or hardware devices and linked into programs
- written for the AlertDriver Class Library with no change to
- the underlying application logic or AlertableObject source
- code.
-
- With the concepts described to this point and their inherent
- programming power and flexibility, most class libraries
- would stop here. However, the AlertDriver Class Library
- provides solutions to even more programming problems. An
- AlertDriver object itself can reference another AlertDriver
- object, effectively chaining, or linking, the AlertDrivers.
- By linking the AlertDrivers for an AlertableObject, the
- AlertableObject can report a single error in multiple ways
- (for example, an error can be reported to the screen and
- logged in a disk file). AlertDrivers can be attached and
- detached from AlertableObjects in any combination at either
- compile-time or run-time for maximum program efficiency and
- flexibility.
-
- Each AlertDriver can also have its actions controlled at
- either compile-time or run-time via a set of processing
- flags. Error-handling, for example, can be temporarily
- turned on or off for each AlertDriver without the need to
- disconnect or destroy the driver. Other useful processing
- flags, which allow a tremendous amount of control over the
- AlertDriver during run-time, are also available.
-
- The AlertDriver library also mirrors the concepts of client-
- server technology: each AlertableObject can be considered
- to be a client, each AlertDriver a server. The client
- initiates an action (i.e.: report an error message) and
- each server has the ability to perform that action. Multiple
- clients can be attached to a single server and a client may
- be served by multiple servers.
-
- The ability to connect several AlertableObjects to the same
- AlertDriver allows applications to retain all of the
- advantages previously discussed while minimizing the amount
- of memory overhead needed to implement those features. For
- example, in a spreadsheet application, each spreadsheet
- object could can be derived from an AlertableObject. If each
- cell required its own AlertDriver, then available memory
- would decrease rapidly as the spreadsheet grew. However, by
- allowing each cell to share a common AlertDriver, the memory
- needed to implement AlertDriver processing is held to a
- small, fixed amount (the amount needed to allocate the
- common AlertDriver). Since all cells in a spreadsheet
- normally report errors in the same manner anyway, the
- unnecessary allocation of duplicate AlertDriver objects is
- avoided.
-
- In the next chapter, we will discuss how easily your
- programs can use the AlertDriver Class Library as we step
- through a tutorial.
-
-
-
- Chapter 3 An AlertDriver Tutorial
-
-
- Creating New Objects
-
- To use the AlertDriver Class Library, you must include the
- following line in your source code file:
-
- #include <alertobj.h>
-
- The ALERTOBJ.H header file contains the declaration for the
- AlertableObject class. (The implementation of the
- AlertableObject class is supplied in a separate object code
- file which is platform-dependent - see the Compiling &
- Linking chapter for details on compiling and linking your
- code with the supported compilers/platforms.)
-
- To create classes of your own, you simply derive your class
- from AlertableObject using public inheritance. (For purposes
- of demonstration, we will present a simple, and admittedly
- contrived, sample class named Integer, which by itself
- doesn't really do anything useful, but will allow us to
- demonstrate the proper syntax and implementation of the
- AlertDriver library concepts - sample platform-independent
- source code implementing Integer is included with the
- AlertDriver Class Library.) Your class will automatically
- inherit the member functions and data of AlertableObject
- (see Example 7).
-
- Example 7 - To derive your own classes, derive your class
- from AlertableObject using public inheritance.
-
- class Integer : public AlertableObject
- {
- ...
- /*declare class-specific member
- functions and data members here*/
- ...
- }; //class Integer
-
-
- Programmer-Defined Codes, Detection, & Reporting
-
- Once you have inherited the capabilities of the
- AlertableObject class, you will want to access that
- functionality from your member functions. There are two
- basic ways of using the AlertableObject member functions to
- alert the user of program conditions: the "quick-and-dirty"
- method and the "preferred" method.
-
- The Quick-And-Dirty Reporting Method
- The quick-and-dirty method of using the AlertDriver Class
- Library is usually used during program testing and/or
- debugging. Using this method, your object passes a literal
- string to the attached AlertDriver to alert the user of the
- program's condition. The quick-and-dirty method retains the
- platform-independent output of the AlertDriver, but the
- messages themselves are hard-coded into the program, clearly
- not the most elegant solution. However, this method is the
- quickest and easiest to use for quickly getting a test
- program to work or for porting existing programs to the
- AlertDriver Class Library. Programs written using the quick-
- and-dirty method can easily be ported to the preferred
- method later.
-
- To use the quick-and-dirty method, your code calls one of
- the Report*() member functions. There are four such
- functions (see the Class Library Reference chapter for
- details), one for each type of alert: ReportError(),
- ReportInfo(), ReportMessage(), and ReportWarning().
- (ClearMessage(), a related function used in conjunction with
- member function ReportMessage(), clears the last message
- posted.)
-
- Example 8 shows how the code in Integer::TestAlertDriver()
- makes calls to these functions, passing literal strings to
- each; the AlertDriver for the Integer object reports those
- strings to the appropriate output device/platform.
-
- Example 8 - Calling the Report*() member functions inherited
- from AlertableObject. Each of these inherited functions
- passes the string along to the object's AlertDriver.
-
- void Integer::TestAlertDriver(void)
- {
- ...
- //test literal strings
- ReportMessage("Literal: This is a message string.");
- ReportError("Literal: This is an error string.");
- ReportWarning("Literal: This is a warning string.",
- adsYES);
- ClearMessage();
- }; //member function Integer::TestAlertDriver
-
- One final note on reporting alerts: the Report*() function
- should always be called from the member function where the
- alert is first encountered or generated. By consistently
- following this suggestion, the code which calls your member
- functions can be written to assume that any alerts occurring
- within your member functions have already been reported by
- the time the function returns.
-
-
- The Preferred Reporting Method
-
- The preferred method of reporting alerts requires a bit more
- work than the quick-and-dirty method, but results in code
- which is infinitely more reusable and flexible. We highly
- suggest that any new programs and/or objects be written
- using the preferred method of alert reporting, as the
- preferred method results in programs which are better
- structured than programs using the quick-and-dirty method.
-
- Before we explain how to use the preferred method, we must
- first discuss the concepts of using programmer-defined codes
- for the alerts. Each unique alert for a class can be
- assigned a unique constant value for that type of alert
- within the class. For example, the error codes for the
- Integer object are numbered starting at one (1). Each unique
- warning alert for the Integer object is also represented
- with a code, with the first warning also being number one
- (1). The fact that both alerts have a code numbered one (1)
- does not cause a conflict - each type of code is used in its
- own context. Using constants (or #defines) to represent
- these codes in your program will help both you and other
- programmers to identify the different contexts when
- reviewing your code (see Example 9). While you may use
- negative numbers as alert code constants, do not use zero
- (0) as an identifier for an alert code - zero is pre-defined
- by the AlertDriver Class Library for each alert type as the
- constants errOK, infoOK, msgOK, and warnOK. Alert codes are
- represented by long integers.
-
- Example 9 - Define constants to uniquely identify each alert
- within a class. Each constant for a particular type of alert
- within a class may have the same value as the constant
- identifier of another alert type in the same class. Each
- constant may also be equal to constants of the same alert
- type in other classes.
-
- ...
- //define alert constants for class Integer
- const long errIntDivByZero = 1;
- const long errIntOverflow = 2;
- const long infoIntConstruct = 1;
- const long msgIntDestruct = 1;
- const long warnIntChange = 1;
- /*legal - different types of alerts*/
- ...
- //define alert constants for class DiskFile
- const long errDiskFileNotFound = 1; //legal
- const long errDiskFileDiskFull = 1;
- /*illegal - same error code (1) defined
- twice for same class*/
- ...
-
- Because errors are the most serious types of alerts, they
- should be returned from member functions whenever possible.
- This means each member function should return the error code
- of any error generated within that function, or return the
- error code returned by functions it calls. By adhering to
- this principle, the program module which calls your member
- functions will always receive an error code denoting the
- first error encountered during execution of your function.
- Of course, your functions should return errOK if no errors
- occur.
-
- The use of programmer-defined alert codes figures
- prominently in the preferred method of alert presentation.
- Rather than call the Report*() member functions, your member
- functions call the inherited Handle*() member functions.
- Each Handle*() member function corresponds to one of the
- Report*() member functions; the Handle*() member functions
- are: HandleError(), HandleInfo(), HandleMessage(), and
- HandleWarning().
-
- Each of the Handle*() functions is passed an alert code as a
- parameter. This alert code is then passed to one of the
- Get*Text() member functions, converted to text, and the text
- is passed to one of the Report*() functions. Of course,
- there are four Get*Text() member functions: GetErrorText(),
- GetInfoText(), GetMessageText(), and GetWarningText().
- To use the preferred method of alerting, your object must
- declare the appropriate alert constants for alerts which can
- be generated within your object. You then override the
- Get*Text() functions to convert those constants to strings.
- In a well-developed class hierarchy, if your Get*Text()
- function receives an alert constant which it cannot convert,
- it should call the overridden Get*Text() function, as the
- constant may represent an alert which was defined in a
- parent class. The original Get*Text() member functions in
- AlertableObject produce generic messages (i.e.: "Error 422
- encountered.") for unrecognized alert codes. Example 10
- shows the implementation of the GetErrorText() member
- function for the Integer class.
-
- Example 10 - Implementation of Integer::GetErrorText()
- member function. Notice how error codes which are
- unrecognized by this class are passed back to the overridden
- function.
-
- ...
- //define error constants for class Integer
- const long errIntDivByZero = 1;
- const long errIntOverflow = 2;
- ...
- class Integer : public AlertableObject
- {
- ...
- public:
- virtual void GetErrorText(const long errorCode, char
- *text);
- ...
- }; //class Integer
- ...
- void Integer::GetErrorText(const long errorCode, char *text)
- {
- switch (errorCode)
- {
- case errIntDivByZero : strcpy(text, "Divide by zero in
- Integer object.");
- break;
- case errIntOverflow : strcpy(text, "Value too large
- for Integer object.");
- break;
- default :
- AlertableObject::GetErrorText(errorCode, text);
- break;
- }; //switch statement to determine error text
- }; //member function Integer::GetErrorText
-
- To invoke the use of your strings in your member functions,
- you simply call the appropriate Handle*() member function,
- passing the correct alert constant. As always, you should
- call the appropriate Handle*() member function from the
- member function where the alert is first encountered.
- Because the Handle*() member functions automatically call
- the Get*Text() and Report*() member functions, a simple call
- to the appropriate Handle*() member function sets the entire
- chain of events into motion.
-
- At first, this may seem like a roundabout way of doing
- things, until you realize the amount of flexibility and
- reusability that your code gains. Because the Get*Text()
- member functions are virtual, you can override them in
- descendant classes. If you don't like the text for a
- specific alert code, you can derive a new class and return a
- different string for the code, even if you don't have the
- source code for the original class. The Get*Text() member
- functions don't even have to store the alert text in the
- program; the functions can be written to retrieve the alert
- text from an external text file. Using an external file to
- store the strings for each alert allows an application to
- use a minimal amount of program memory to store text. In
- addition, the text file can later be altered to update
- existing alert text without requiring recompilation of the
- application. Coupled with the platform-independent output of
- the AlertDriver, these capabilities give every
- AlertableObject maximum flexibility in presenting alerts to
- the user.
-
- Example 11 demonstrates how the overloaded "/" operator
- handles errant attempts to divide Integer objects by zero.
-
- Example 11 - The overloaded operator member function
- Integer::operator /() calls inherited member function
- HandleError() whenever it detects an attempted divide by
- zero. Invoking the HandleError() member function causes an
- eventual call to the Integer::GetErrorText() member function
- shown in Example 10.
-
- int Integer::operator / (int aValue)
- {
- int result; //holds the function result
-
- if (aValue)
- //specified value is not 0
- result = val / aValue;
- else
- {
- HandleError(errIntDivByZero);
- result = INT_MAX;
- }
- return result;
- }; //overloaded operator Integer::operator /
-
-
-
- Changing & Sharing AlertDrivers
-
- All programs linked with the AlertDriver Class Library
- automatically gain access to a default AlertDriver
- referenced by the defaultAlertDriver pointer (defined in
- ALERTDRV.H). This global AlertDriver is usually an
- interactive, screen-oriented driver which provides alert
- reporting capabilities for the software environment for
- which the program was targeted. For example,
- defaultAlertDriver may provide text-mode output for a text-
- mode program, but will use Windows dialog boxes if the
- program has been compiled as a Windows application. Because
- defaultAlertDriver is available to be called from any part
- of your application, even your non-object code can call
- defaultAlertDriver's member functions (see Example 12).
- Calling one of the Handle*() member functions of the
- AlertDriver class is equivalent to calling one of the
- AlertableObject::Report*() member functions (see the Class
- Library Reference for details).
-
- Example 12 - Accessing defaultAlertDriver's member functions
- from non-object code. Calls made in this way are roughly
- equivalent to the quick-and-dirty method of reporting alerts
- from within objects.
-
- #include <alertdrv.h>
- ...
- void main(void)
- {
- ...
- //test the defaultAlertDriver without an object
- defaultAlertDriver->HandleInfo(
- "Text from non-object code.");
- ...
- }; //function main()
-
- Each AlertableObject (and derived object) that is created by
- your program initially uses the defaultAlertDriver as its
- AlertDriver. By using this common AlertDriver, the
- AlertableObjects in your program gain all of the benefits of
- platform-independent error reporting with a minimum of
- code/data overhead. One AlertDriver controls the alerts of
- all your program's objects.
-
- There are times, however, when you may want to change this
- default behavior, particularly if the default AlertDriver
- does not provide the appropriate type of output for your
- object. For example, although the default AlertDriver is
- usually screen-oriented, your may want your object to log
- alerts to a disk file.
-
- You can easily change the type of AlertDriver used by your
- object by calling the
- AlertableObject::ChangeLinkedAlertDriver() member function.
- To call this inherited member function, you create a new
- AlertDriver object, then pass its address as a parameter to
- the function. Because all AlertDrivers should be allocated
- on the heap, this can usually be accomplished with one line
- of code. For example, the following line of code will change
- the AlertDriver for object MyObj to an AlertDriver which
- logs alerts to a text file named "myobj.log":
-
- MyObj.ChangeLinkedAlertDriver(new
- TextFileAlertDriver("myobj.log", radFREERESOURCE));
-
- (The radFREERESOURCE constant forces the TextFileAlertDriver
- to free (close) the file whenever it is not in use; when the
- file is closed (not recording alerts), it can be accessed by
- other TextFileAlertDrivers or other applications. See the
- Class Library Reference for more details on controlling the
- TextFileAlertDriver.)
-
- AlertDrivers allocated by your application can serve several
- AlertableObjects at once, just as the default AlertDriver
- originally serves all of the objects in your program as they
- are created. Example 13 demonstrates how to share one newly
- allocated AlertDriver among two objects.
-
- Example 13 - Creating an AlertDriver object and sharing it
- among multiple objects. In this case, both objects will log
- their alerts to the same text file. Remember, AlertDrivers
- which you create within your program should always be
- allocated on the heap.
-
- ...
- AlertDriver *pAlertDriver;
- Integer a, b;
- ...
- /*log a and b alerts to the same text file -
- other AlertableObjects continue to use
- defaultAlertDriver*/
- pAlertDriver =
- new TextFileAlertDriver("myobjs.log",
- radFREERESOURCE);
- a.ChangeLinkedAlertDriver(pAlertDriver);
- b.ChangeLinkedAlertDriver(pAlertDriver);
- ...
-
- To completely remove (not replace) the AlertDriver for an
- AlertableObject, call member function
- ChangeLinkedAlertDriver() with a parameter of NULL; doing
- this will remove all alerting capabilities for the
- AlertableObject.
-
- The AlertDriver Class Library defines the standard classes
- StdAlertDriver and TextFileAlertDriver for all software
- platforms and environments. StdAlertDriver uses the standard
- C++ iostreams cin, cout, and cerr to report alerts to the
- user while TextFileAlertDriver logs alert text to a file
- which is specified in its constructor. Additional
- AlertDriver classes may be defined for your specific
- software environment (for example, class
- TurboVisionAlertDriver is defined for programs using
- Borland's Turbo Vision class library). See the Class Library
- Reference chapter for full details on the AlertDriver
- classes which are available in your specific software
- environment.
-
- Experienced programmers know that one of the toughest parts
- of debugging a program is finding heap allocation errors.
- Because all AlertDrivers are allocated on the heap and may
- be shared among multiple AlertableObjects, you may be
- wondering if there is an easy way to determine when an
- AlertDriver is no longer being used and when it is safe to
- deallocate an AlertDriver. The answer is simple: you don't
- have to worry about deallocating any AlertDrivers, even
- those which you allocate! The AlertDriver Class Library
- handles it all for you!
-
- Each AlertDriver contains a count of the number of
- AlertableObjects using its services. This count is
- incremented each time an AlertDriver is "attached" to an
- AlertableObject. An AlertableObject is "detached" from an
- AlertDriver whenever the AlertableObject is deallocated,
- goes out of scope, or is attached to a different AlertDriver
- object through member function ChangeLinkedAlertDriver();
- each time this happens, the attached AlertDriver's count is
- decremented. When the count reaches zero (the AlertDriver is
- no longer being used by any object), the AlertDriver is
- automatically shutdown and deallocated. What this means to
- you as a programmer is that you can allocate as many
- AlertDrivers of as many different classes as necessary and
- attach them to as many AlertableObjects as you desire with
- the understanding that each of the AlertDrivers will be
- deallocated as soon as it is no longer being used.
-
-
- Linking AlertDrivers
-
- Although you can change the AlertDriver used for each of
- your objects at any time, this still may not give you the
- level of flexibility you need. After all, it's nice to be
- able to switch between screen-based alerting and logging
- those alerts to a disk file, but what if you wanted to do
- both at the same time? With the AlertDriver Class Library,
- you can attach several AlertDrivers together in series so
- that the same alerts are reported in multiple ways. This
- process is known as "linking" the AlertDrivers.
-
- To link one AlertDriver to another, you must call the
- ChangeLinkedAlertDriver() member function of the first
- AlertDriver object. (The first AlertDriver object is defined
- as the AlertDriver which is attached to an AlertableObject,
- the remaining AlertDrivers are each attached to the
- previously linked AlertDriver. In effect, the AlertDrivers
- form a linked list, often referred to as a "chain.") A
- common use of linking AlertDrivers is to provide disk file
- logging in addition to screen alerting by linking a
- TextFileAlertDriver to an AlertableObject's AlertDriver.
- This can be most easily accomplished if the
- AlertableObject's AlertDriver is the default AlertDriver
- (see Example 14).
-
- Example 14 - By linking a TextFileAlertDriver to the default
- AlertDriver, all objects using the default AlertDriver will
- report their alerts to both the screen and a disk file
- (assuming that the default AlertDriver reports alerts to the
- screen).
-
- ...
- //attach a text file AlertDriver to the default driver
- defaultAlertDriver->ChangeLinkedAlertDriver(
- new TextFileAlertDriver("adtest.log", radFREERESOURCE));
- ...
-
- It is important to note that when you call
- AlertableObject::ChangeLinkedAlertDriver() or
- AlertDriver::ChangeLinkedAlertDriver(), you are effectively
- replacing all AlertDrivers which are linked to the
- object/driver with the AlertDriver you specify. For
- illustration, assume that prior to calling the code in
- Example 14, defaultAlertDriver is the first of four (4)
- AlertDrivers which are linked together. After executing the
- code in Example 14, defaultAlertDriver will be the first of
- two (2) AlertDrivers in the link. The three AlertDrivers
- which were linked to defaultAlertDriver prior to the
- ChangeLinkedAlertDriver() call were detached from
- defaultAlertDriver (and possibly deallocated if they were
- not being used by other objects).
-
- This concept works in the other direction as well. You can
- link several AlertDrivers together, than pass the address of
- the first one to ChangeLinkedAlertDriver(); the first
- AlertDriver will be directly attached to the object/driver
- for which the call was made, while all other AlertDrivers in
- the link will be indirectly attached to the same
- object/driver.
-
- When several AlertDrivers are linked together, the first one
- processes the alert from the AlertableObject, then passes
- the alert to the next linked AlertDriver. This process
- continues until there are no more AlertDrivers in the chain.
- Because of this series of actions, it is suggested that you
- place only one screen-oriented AlertDriver in any
- AlertDriver chain. We also recommend that the screen-
- oriented AlertDriver (or any AlertDriver which interacts
- with the user) be placed first in the chain - this not only
- allows the user to be notified immediately of any alerts,
- but also ensures that other AlertDrivers in the chain are
- informed of the user's choice. For example, if an
- AlertDriver chain contained both a StdAlertDriver and a
- TextFileAlertDriver, you should place the StdAlertDriver
- first because it interacts with the user. In this case,
- warning alerts would be presented to the user first, then
- the user's choice would be recorded in the text file. Had
- the TextFileAlertDriver been placed first in the chain,
- recording the user's choice correctly in the text file would
- not be possible.
-
-
- Modifying AlertDriver Behavior
-
- At times, you may wish to temporarily disable processing of
- a certain type of alert or affect the output of an alert for
- an AlertableObject without changing or detaching the
- AlertDriver. Such changes can be made by altering the
- processing flags which are stored in each AlertDriver.
- Through the use of AlertableObject member functions
- GetAlertProcFlags() and ChangeAlertProcFlags(), you can
- obtain and alter the settings of the linked AlertDriver(s)
- for an object. (You can directly get/set the processing
- flags for an AlertDriver by calling its member functions
- GetProcFlags() and ChangeProcFlags() - see the Class Library
- Reference chapter for details and syntax.)
-
- The processing flags for an AlertDriver are represented as
- bit-mapped constants prefixed with the letters "adf" in the
- ALERTDRV.H header file. Four of these constants act as
- switches for processing the various types of alerts:
- adfERROR, adfINFO, adfMESSAGE, and adfWARNING. When one of
- these flags is enabled (on), the AlertDriver processes all
- alerts of that type which are passed to it. When a flag is
- disabled (off), the AlertDriver ignores alerts of that type,
- but still passes the alert to the next linked AlertDriver
- (if any).
-
- The return value of AlertableObject::GetAlertProcFlags() is
- an unsigned short which holds the value of all flags
- currently enabled for the first linked AlertDriver for the
- object. You can test to see if a flag is enabled (on) by
- performing a binary "AND" operation:
-
- //see if the first-linked AlertDriver for MyObj is currently
- processing warnings
- if (MyObj.GetAlertProcFlags() & adfWARNING)
- {
- //warnings are being processed for MyObj
- ...
- }
-
- Example 15 shows how to enable or disable processing for a
- specific type of alert using the
- AlertableObject::ChangeAlertProcFlags() member function; the
- second parameter determines whether the specified flags are
- enabled (cfoENABLE), disabled (cfoDISABLE), or intended to
- overwrite all of the current flags (cfoOVERWRITE) as well as
- whether the changes are made for the first AlertDriver
- (cfoDRIVER) or for all linked AlertDrivers (cfoCHAIN).
- Please see the Class Library Reference for more details.
-
- Example 15 - Enabling and disabling AlertDriver processing
- flags for an Integer object. Notice that when enabling or
- disabling specific flags, other flags for the AlertDriver
- are not altered. In this example, the first linked
- AlertDriver for object "a" is assumed to be a screen-
- oriented interactive AlertDriver; this is normally the case.
-
- ...
- Integer a;
- ...
- /*temporarily disable information alert
- processing to the screen for a*/
- a.ChangeAlertProcFlags(adfINFO, cfoDRIVER | cfoDISABLE);
- /*now perform operations on a which are likely to
- generate information alerts*/
- ...
- //enable information alert processing for a
- a.ChangeAlertProcFlags(adfINFO, cfoDRIVER | cfoENABLE);
- ...
-
- The adfALLALERTS flag is a combination of the adfERROR,
- adfINFO, adfMESSAGE, and adfWARNING flags.
-
- The adfTIMESTAMP flag controls whether an alert is
- timestamped when reported. When enabled, this flag causes
- the AlertDriver to generate a string holding the current
- date/time and appends the alert text to that string. The
- timestamp is formatted with the standard ANSI C function
- ctime() (see the Class Library Reference chapter for
- details.) A typical timestamped error message output through
- a TextFileAlertDriver might look like:
-
- Tue Dec 28 15:18:36 1993
- ERROR - Literal: This is an error string.
-
- By this point, you've no doubt realized that a warning is
- the only type of alert which needs to return information to
- the program. When calling member function
- AlertableObject::HandleWarning(), you not only specify a
- string containing a question for the user, but you also
- indicate the default response to the question (please see
- the Class Library Reference chapter for details). If warning
- processing is enabled for the object's first linked
- AlertDriver, the question is presented to the user and the
- response is returned. However, this is one of only three
- possible states for the AlertDriver; warning processing may
- be disabled for the AlertDriver, or the object may not
- currently be attached to an AlertDriver. In the latter case,
- AlertableObject::HandleWarning() returns a constant
- indicating that no AlertDriver is attached to the object.
- But what should be returned in the former case?
-
- By default, if warning processing is disabled for the
- AlertDriver, the value returned is the default value you
- specified. Your program can assume that the user chose the
- default option and execution continues normally. However,
- there may be times when you want to know that the user was
- not given the opportunity to make a choice. In this case,
- you should enable processing flag adfDISCLOSURE for the
- AlertDriver. When adfDISCLOSURE is enabled and adfWARNING is
- disabled, calls to AlertableObject::HandleWarning() result
- in a special constant being returned; this constant
- indicates that processing for the current alert was
- disabled.
-
- Please see the discussion of
- AlertableObject::HandleWarning() in the Class Library
- Reference for full details of that member function's
- possible return values and how your code should deal with
- them.
-
- In most cases, the default settings of each AlertDriver's
- processing flags should be adequate for your application.
- Remember, when setting the processing flags for an
- AlertDriver which is shared between objects, you will be
- affecting the alert processing for all of those objects.
-
-
- What About Exception Handling?
-
- Because exception handling (a fairly new C++ language
- feature) is not supported by all C++ compilers (and not
- implemented consistently among those compilers which do
- support it), we will not attempt to show sample code for
- using this feature. However, this does not mean that the
- AlertDriver Class Library is incompatible with exception
- handling concepts.
-
- Exception handling allows for the separation of a program's
- error-generation code from the error-reporting/handling
- code. This is implemented through a try block (which
- contains a program's/routine's "normal" code) and one or
- more catch blocks (which handle the errors occurring within
- the try block.) Whenever a program exception (an exceptional
- condition, such as an error) occurs within the try block,
- the program executes a throw (raises the exception) and
- control is passed to one of the catch blocks.
-
- Once the exception reaches the catch block, the exception-
- handling code can be reported using an AlertDriver. Even if
- your objects have been written to throw exceptions, they
- themselves can catch the exceptions, report them using their
- linked AlertDriver(s), then re-throw the exceptions to
- higher-level code.
-
- If you plan to use exception handling in your C++ programs,
- we suggest that you use the AlertDriver Class Library as a
- environment- and device-independent means of reporting those
- exceptions. The concepts of the AlertDriver Class Library
- are a natural supplement to those of exception handling.
-
-
- Application Design Techniques - A Summary
-
- By now, you've read all about the power and flexibility of
- the AlertDriver Class Library. Compiled below are what we
- have found to be the most important coding and design
- techniques to use when writing applications for the
- AlertDriver Class Library.
- 1.Always invoke the appropriate handling for an alert in
- the member function in which the alert is first
- generated; this helps make your objects self-contained by
- allowing them to process their own alerts.
- 2.Whenever possible, return error codes from your member
- functions. This practice allows calling code to determine
- if your member functions were successful.
- 3.Use the preferred method of alerting whenever possible.
- This requires that your class be designed so that alert
- constants can be defined early in development, but
- rewards you with highly reusable code. By following this
- practice, the text for each alert can be stored
- externally and/or altered by descendant classes.
- 4.Use positive or negative numbers to represent alert
- constants, but never use zero (0). Zero should indicate
- that nothing is wrong.
- 5.Always try to share AlertDrivers among objects whenever
- possible, as this minimizes memory usage. However, you
- should give an object its own (non-shared) AlertDriver if
- you will be altering its processing flags; this practice
- will prevent the inadvertent processing changes of alerts
- from other objects.
- 6.Use the AlertDriver referenced by defaultAlertDriver for
- environment-independent alerting for non-object-oriented
- code.
- 7.Always create AlertDrivers on the heap. When they are no
- longer used, they will automatically be deallocated by
- the AlertableObject(s) which use them.
- 8.Link AlertDrivers whenever you need to provide alerting
- to multiple output devices. Linking can take place at
- compile-time or at run-time.
- 9.Modify an AlertDriver's processing flags whenever you
- need to enable or disable the output of certain types of
- alerts either temporarily or for the object's lifetime.
- Processing flags can be altered at compile-time or at run-
- time.
-
-
-
- Chapter 4 Compiling & Linking
-
- IMPORTANT: This chapter describes how to compile and
- link your programs to use the AlertDriver Class
- Library. You should read this section in its
- entirety before using the AlertDriver Class
- Library.
-
-
- Supported Compilers & Class Libraries
-
- As of the printing of this manual, the AlertDriver Class
- Library has been successfully tested with the following
- compilers/class libraries:
- Borland C++ v3.1 (text mode, Container Class Library,
- Turbo Vision, ObjectWindows)
- Microsoft C/C++ v7.0 (text mode)
-
- Other untested compilers/class libraries may be supported in
- text mode. You should read the supplied file named
- "README.1ST" on the distribution disks for the latest
- information which may describe features/updates added after
- the printing of this manual.
-
-
- Header Files
-
- There are four header files associated with the AlertDriver
- Class Library:
- ADWINDLL.H Prototypes of functions used in Microsoft
- Windows helper DLL.
- ALERTDRV.H AlertDriver class (and derivatives)
- declarations.
- ALERTOBJ.H AlertableObject class declaration.
- ENVIRON.H Compilation- and target-specific declarations.
-
- You will normally #include the ALERTOBJ.H and/or ALERTDRV.H
- header files in your source code files to give the compiler
- the necessary class declarations and/or function prototypes.
- (The Class Library Reference chapter lists the appropriate
- header file for each identifier which your program may need
- to access from the AlertDriver Class Library.)
-
- The ADWINDLL.H header file is automatically #included by the
- AlertDriver Class Library whenever you compile your program
- for the Microsoft Windows platform. You will normally not
- need to be concerned with this file.
-
- The ENVIRON.H header file is a special file which contains
- all of the compilation- and target-specific declarations
- needed to compile your program for different environments.
- You may need to replace the first two (2) #define statements
- in ENVIRON.H to compile your program for the appropriate
- environment (see below). Don't worry: this is extremely
- easy to do and the header file itself is clearly documented!
-
-
- Changing The Compilation Environment #define in ENVIRON.H
-
- The first #define statement in the ENVIRON.H header file
- defines the compilation environment and class library to be
- used. You should replace the #define with one of the valid
- entries listed below. Your choice of compilation environment
- will cause the compiler to make several assumptions
- (detailed below) about your code. The valid compilation
- environment #defines are:
- BORLAND_CONTAIN Borland's Container Class Library.
- OBJECT.H will be #included and the
- AlertDriver Class Library classes will be
- derived from Object.
- BORLAND_OWL Borland's ObjectWindows Library. Because
- Borland's Windows Custom Controls Library is
- used to present some alerts in customized
- dialog boxes, BWCC.H will be #included
- (BWCC.H is supplied with the Borland C++
- compiler). OBJECT.H will also be #included
- and the AlertDriver Class Library classes
- will be derived from Object.
- BORLAND_TV Borland's Turbo Vision Class Library.
- #defines several Turbo Vision Uses_*
- preprocessor definitions, then #includes the
- TV.H header file. The AlertDriver Class
- Library classes will be derived from TObject.
- When you #define this compilation
- environment, you should #define your
- program's Turbo Vision Uses_* preprocessor
- directives before #including any of the
- AlertDriver Class Library header files. See
- the Turbo Vision documentation for more
- details.
- NOROOT The AlertDriver Class Library classes will be
- compiled without a common root class.
-
-
- Changing The Target Environment #define In ENVIRON.H
-
- The second #define statement in the ENVIRON.H header file
- defines the target environment for the executable file to be
- produced. You should replace the #define with one of the
- valid entries listed below. Your choice of target
- environment will cause the compiler to make several
- assumptions (detailed below) about your code. The valid
- target environment #defines are:
- TARGET_DOS The program will run under the Microsoft DOS
- (or compatible) operating system.
- TARGET_WINDOWS The program will run under the Microsoft
- Windows (or compatible) operating
- environment. Header file ADWINDLL.H is
- #included (this indirectly #includes
- WINDOWS.H). When you #define this target
- environment, you should #define your
- program's WINDOWS.H preprocessor directives
- (if any) before #including any of the
- AlertDriver Class Library header files.
-
- Of course, not every combination of compilation environment
- and target environment is valid, so make sure that the
- combination you choose makes sense (if it doesn't, the
- compiler will usually give you an error). For example, the
- #defines shown here are illegal:
-
- #define BORLAND_OWL //use ObjectWindows Library
- #define TARGET_DOS //ILLEGAL - cannot compile OWL apps as
- DOS apps
-
- The correct settings for ENVIRON.H for this example would
- be:
-
- #define BORLAND_OWL //use ObjectWindows Library
- #define TARGET_WINDOWS //OWL apps must be Windows apps
-
-
- Linking Your Programs
-
- To link your programs, you must link the appropriate library
- to your application in your MAKE or PROJECT file (see your
- compiler manual for details on linking). Refer to the lists
- below for the appropriate library for your compilation
- environment, target environment, and memory model.
-
- IMPORTANT - Make sure you link your programs to the right
- library. If you link the wrong library, your
- program will not execute.
-
- If you #defined TARGET_DOS in ENVIRON.H as your target
- environment:
- Link with one of the following libraries, whichever is
- appropriate for the setting you #defined for the
- compilation environment in ENVIRON.H and your program's
- memory model:
- ADBRDCCx.LIBBorland C++ Container Classes - There
- are six of these files, where x = the
- first letter of the memory model
- (tiny, small, medium, compact, large,
- or huge). For example, ADBRDCCL.LIB
- is for use with large memory model
- programs.
- ADBRDNRx.LIBBorland C++, no root class - There
- are six of these files, where x = the
- first letter of the memory model
- (tiny, small, medium, compact, large,
- or huge). For example, ADBRDNRL.LIB
- is for use with large memory model
- programs.
- ADBRDTVL.LIBBorland C++ Turbo Vision - large
- memory model.
- ADMSDNRx.LIBMicrosoft C/C++, no root class -
- There are four of these files, where
- x = the first letter of the memory
- model (small, medium, compact, or
- large). For example, ADMSDNRL.LIB is
- for use with large memory model
- programs.
- If you #defined BORLAND_TV as the compilation
- environment, link this file:
- TV.LIB Borland's Turbo Vision library
- (supplied with the Borland C++
- compiler).
-
- If you #defined TARGET_WINDOWS in ENVIRON.H as your target
- environment:
- Link with one of the following libraries, whichever is
- appropriate for the setting you #defined for the
- compilation environment in ENVIRON.H and your program's
- memory model:
- ADBRWCCx.LIBBorland C++ Container Classes - There
- are four of these files, where x =
- the first letter of the memory model
- (small, medium, compact, or large).
- For example, ADBRWCCL.LIB is for use
- with large memory model programs.
- ADBRWNRx.LIBBorland C++, no root class - There
- are four of these files, where x =
- the first letter of the memory model
- (small, medium, compact, or large).
- For example, ADBRDNRL.LIB is for use
- with large memory model programs.
- ADBRWOWx.LIBBorland C++ ObjectWindows Library -
- There are four of these files, where
- x = the first letter of the memory
- model (small, medium, compact, or
- large). For example, ADBRWOWL.LIB is
- for use with large memory model
- programs.
- Also link this file:
- ADWINDLL.LIBImport library for the file
- ADWINDLL.DLL; make sure you
- distribute ADWINDLL.DLL with your
- finished application!
- If you #defined BORLAND_OWL as the compilation
- environment, link this file:
- BWCC.LIB Import library for Borland's Custom
- Control Library for Windows (supplied
- with the Borland C++ compiler); make
- sure you distribute BWCC.DLL with
- your application!
-
-
- Compiler-Specific Notes
-
- When writing programs which use the AlertDriver C++ Class
- Library, you may need to know how the supplied object code
- was compiled. The notes below indicate the compiler settings
- used to compile the AlertDriver Class Library. You may want
- to consider purchasing the Source Code Edition of the
- AlertDriver C++ Class Library if you want to recompile the
- AlertDriver Class Library with different compiler settings.
-
-
- Borland C++ v3.1
-
- All object code libraries and DLLs were compiled assuming
- that all unsigned char variables should be explicitly
- defined (unsigned chars off). Stack checking was turned off.
- DOS libraries were compiled with 8086/8088 instructions.
- Windows libraries were compiled with 80286 instructions,
- target Windows 3.0 and above, and assume the use of the
- static versions of the standard, Container Class, and/or
- ObjectWindows libraries.
-
-
- Microsoft C/C++ v7.0
-
- Stack checking was turned off and the libraries were
- compiled with 8086 instructions.
-
-
- Compiling The Sample Programs
-
- To compile any of the sample programs, you should follow all
- of the rules and suggestions previously mentioned in this
- chapter. Don't forget to correctly #define the compilation-
- and target-environment macros in ENVIRON.H!
-
- The sample file INTDEMO.CPP is the main file for the sample
- program using the Integer class. (The Integer class is
- discussed in the Tutorial Chapter.) To compile this program,
- you should compile the INTDEMO.CPP and INTEGER.CPP files,
- then link them with the appropriate AlertDriver Library .LIB
- file(s). These files can be compiled for any of the
- supported compilation- and/or target-environments.
-
- If you want to compile the INTDEMO.CPP sample program as a
- Windows application, you should also link the ADWIN.DEF
- module definition file to your executable.
-
- Note that the source code for the Integer class (in
- INTEGER.CPP), and the INTDEMO.CPP functions which manipulate
- the Integer objects, are totally compilation- and target-
- environment independent.
-
-
-
- Class Hierarchy
-
- In the listing below, derivative classes are indented
- underneath their parent class. For example, class
- WindowsAlertDriver is derived from class AlertDriver, which
- is derived from class AlertDriverLink.
-
- ROOTCLASS
- AlertDriverLink
- AlertableObject
- AlertDriver
- RecordingAlertDriver
- StreamAlertDriver
- TextFileAlertDriver
- StdAlertDriver
- TurboVisionAlertDriver
- WindowsAlertDriver
- BWCCAlertDriver
-
-
-
- Chapter 6 Creating Your Own AlertDrivers
-
-
- Design Concepts
-
- For most of your programming projects, the AlertDriver
- classes shipped with the AlertDriver Class Library will be
- sufficient for your needs. If, however, you would like to
- output alerts using operating-system API calls or hardware
- devices which are not supported by the standard AlertDriver
- Class Library, then you will need to create (subclass) your
- own AlertDriver classes. You may also want to subclass the
- supplied AlertDrivers to change their default behavior. In
- any case, this chapter presents the guidelines which should
- be followed while designing and writing new AlertDriver
- classes.
-
- Before designing your own custom AlertDriver class, you
- should first determine what type of AlertDriver the class
- will be. There are two basic types of AlertDriver classes:
- interactive (those which can interact with the user) and
- recording (those which provide output-only services).
- Interactive AlertDriver classes are derived from the
- AlertDriver class, while recording AlertDrivers are
- subclassed from the RecordingAlertDriver class.
-
- Because interactive AlertDrivers usually report alerts to
- the screen, they should be designed to use standard C, C++,
- or operating-system API calls whenever possible. Recording
- AlertDrivers, however, usually report to hardware devices
- (which are somewhat dependent on the operating-system) such
- as printers or RS-232C devices. Therefore, recording
- AlertDrivers often must be designed to use the API calls
- provided by the hardware device manufacturer.
-
-
- Requirements & Suggestions
-
- To write an AlertDriver class definition, you must have a
- good understanding of the API calls necessary to control the
- output resource, as well as an understanding of the
- class(es) from which you will be subclassing the
- AlertDriver. Of course, you must also have a C++ compiler
- for your target environment, as well as any prerequisites
- for the compiler.
-
- If you are planning to create your own AlertDriver classes,
- we recommend that you purchase the Source Code Edition of
- the AlertDriver Class Library. By examining the well-
- commented source code used to write the supplied AlertDriver
- classes, you can gain a much deeper understanding of the
- techniques used to write reusable AlertDrivers.
-
-
- Updating ENVIRON.H
-
- You will have to update the ENVIRON.H header file if you are
- trying to do one of the following:
- 1.port the AlertDriver Class Library to a new compilation
- environment (i.e.: use a currently-unsupported hierarchy
- class as the root class for the AlertDriver Class
- Library)
- 2.port the AlertDriver Class Library to a new target
- environment (i.e.: target your executable code for a
- currently-unsupported operating system)
- 3.redefine one of the macros specifying an AlertDriver
- system setting (i.e.: specify a different default
- AlertDriver or change the maximum size of an alert text
- string)
-
- If you need to update ENVIRON.H, we suggest you first print
- the file and study its heavily-commented preprocessor
- directives.
-
-
- Defining Your AlertDriver
-
- To define an AlertDriver, you must first plan to override
- the AlertDriver::Report*() member functions. Remember that
- for interactive AlertDrivers, member functions
- ReportError(), ReportInfo(), and ReportWarning() should halt
- program execution until acknowledged by the user. For
- recording AlertDrivers, program execution should never be
- halted. For full details on the intended actions of the
- Report*() member functions for both interactive and
- recording AlertDrivers, see the discussions of the
- AlertDriver::Report*() member functions in the Class Library
- Reference chapter.
-
- If you are writing a recording AlertDriver, you should call
- member function GetResourceControl() from your
- constructor(s), destructor, and Report*() member functions.
- If the resource control mode is radFREERESOURCE or
- radHOLDRESOURCE, your object should explicitly capture and
- free the resource when appropriate. (For the supplied
- TextFileAlertDriver, this is accomplished by opening/closing
- the output file.) Review the discussion of the
- RecordingAlertDriver data member resourceControl in the
- Class Library Reference for more details on controlling the
- output resource for a recording AlertDriver.
-
- You may also want to override the
- AlertDriver::GetTimestamp() member function to return the
- computer's current date/time in a format different from the
- default.
-
- Finally, if your AlertDriver encounters an error during
- output, you should not attempt to display an error message.
- Just clean up any allocated resources and return
- immediately.
-
- That's all there is to creating your own AlertDriver
- objects! If you have followed these guidelines, your
- AlertDriver objects should be usable by any AlertableObject
- without changes to the AlertableObject.
-